From 28b490f14feaea74cbd406a053b30f62e5832005 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sun, 3 Jul 2016 21:12:22 +0100 Subject: [PATCH] gsk: Rework how GLSL shaders are built The GL renderer should build the GLSL shaders using GskShaderBuilder. This allows us to separate the common parts into separate files, and assemble them as necessary, instead of shipping one big shader per type of GL API (GL3, GL legacy, and GLES). --- gsk/gskglrenderer.c | 210 +++++++++++++------------- gsk/resources/glsl/blend.fs.glsl | 22 +++ gsk/resources/glsl/blend.vs.glsl | 6 + gsk/resources/glsl/es2_common.fs.glsl | 16 ++ gsk/resources/glsl/es2_common.vs.glsl | 7 + gsk/resources/glsl/gl3-base.fs.glsl | 34 ----- gsk/resources/glsl/gl3-base.vs.glsl | 16 -- gsk/resources/glsl/gl3_common.fs.glsl | 19 +++ gsk/resources/glsl/gl3_common.vs.glsl | 7 + gsk/resources/glsl/gl_common.fs.glsl | 14 ++ gsk/resources/glsl/gl_common.vs.glsl | 7 + gsk/resources/glsl/gles-base.fs.glsl | 11 -- gsk/resources/glsl/gles-base.vs.glsl | 12 -- 13 files changed, 206 insertions(+), 175 deletions(-) create mode 100644 gsk/resources/glsl/blend.fs.glsl create mode 100644 gsk/resources/glsl/blend.vs.glsl create mode 100644 gsk/resources/glsl/es2_common.fs.glsl create mode 100644 gsk/resources/glsl/es2_common.vs.glsl delete mode 100644 gsk/resources/glsl/gl3-base.fs.glsl delete mode 100644 gsk/resources/glsl/gl3-base.vs.glsl create mode 100644 gsk/resources/glsl/gl3_common.fs.glsl create mode 100644 gsk/resources/glsl/gl3_common.vs.glsl create mode 100644 gsk/resources/glsl/gl_common.fs.glsl create mode 100644 gsk/resources/glsl/gl_common.vs.glsl delete mode 100644 gsk/resources/glsl/gles-base.fs.glsl delete mode 100644 gsk/resources/glsl/gles-base.vs.glsl diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c index d9d6540eb8..fd8ee8db9e 100644 --- a/gsk/gskglrenderer.c +++ b/gsk/gskglrenderer.c @@ -7,6 +7,7 @@ #include "gskrendererprivate.h" #include "gskrendernodeprivate.h" #include "gskrendernodeiter.h" +#include "gskshaderbuilderprivate.h" #include "gskprivate.h" @@ -275,131 +276,135 @@ gsk_gl_renderer_destroy_buffers (GskGLRenderer *self) self->has_buffers = FALSE; } -static guint -create_shader (int type, - const char *code) +static gboolean +gsk_gl_renderer_create_programs (GskGLRenderer *self) { - guint shader; - int status; - - shader = glCreateShader (type); - glShaderSource (shader, 1, &code, NULL); - glCompileShader (shader); - - glGetShaderiv (shader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) - { - int log_len; - char *buffer; + GskShaderBuilder *builder; + const char *vertex_preamble; + const char *fragment_preamble; + int vertex_id = -1, fragment_id = -1; + int program_id = -1; + GError *error = NULL; + gboolean res = FALSE; + enum { + MVP, + MAP, + PARENT_MAP, + ALPHA, + BLEND_MODE, + N_UNIFORMS + }; + enum { + POSITION, + UV, + N_ATTRIBUTES + }; + GQuark uniforms[N_UNIFORMS]; + GQuark attributes[N_ATTRIBUTES]; + + builder = gsk_shader_builder_new (); - glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_len); + gsk_shader_builder_set_resource_base_path (builder, "/org/gtk/libgsk/glsl"); - buffer = g_malloc0 (log_len + 1); - glGetShaderInfoLog (shader, log_len, NULL, buffer); + uniforms[MVP] = gsk_shader_builder_add_uniform (builder, "mvp"); + uniforms[MAP] = gsk_shader_builder_add_uniform (builder, "map"); + uniforms[PARENT_MAP] = gsk_shader_builder_add_uniform (builder, "parentMap"); + uniforms[ALPHA] = gsk_shader_builder_add_uniform (builder, "alpha"); + uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "blendMode"); + + attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "position"); + attributes[UV] = gsk_shader_builder_add_attribute (builder, "uv"); - g_critical ("Compile failure in %s shader:\n%s", - type == GL_VERTEX_SHADER ? "vertex" : "fragment", - buffer); - g_free (buffer); +#define SHADER_VERSION_GLES 110 +#define SHADER_VERSION_GL_LEGACY 120 +#define SHADER_VERSION_GL3 150 - glDeleteShader (shader); + if (gdk_gl_context_get_use_es (self->context)) + { + gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES); + gsk_shader_builder_add_define (builder, "GSK_GLES", "1"); - return 0; + vertex_preamble = "gles_common.vs.glsl"; + fragment_preamble = "gles_common.fs.glsl"; } - - return shader; -} - -static void -gsk_gl_renderer_create_program (GskGLRenderer *self) -{ - guint vertex_shader = 0, fragment_shader = 0; - const char *fs_path, *vs_path; - GBytes *source; - int status; - - if (gdk_gl_context_get_use_es (self->context)) + else if (gdk_gl_context_is_legacy (self->context)) { - vs_path = "/org/gtk/libgsk/glsl/gles-base.vs.glsl"; - fs_path = "/org/gtk/libgsk/glsl/gles-base.fs.glsl"; + gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY); + gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1"); + + vertex_preamble = "gl_common.vs.glsl"; + fragment_preamble = "gl_common.fs.glsl"; } else { - vs_path = "/org/gtk/libgsk/glsl/gl3-base.vs.glsl"; - fs_path = "/org/gtk/libgsk/glsl/gl3-base.fs.glsl"; - } - - GSK_NOTE (OPENGL, g_print ("Compiling vertex shader\n")); - source = g_resources_lookup_data (vs_path, 0, NULL); - vertex_shader = create_shader (GL_VERTEX_SHADER, g_bytes_get_data (source, NULL)); - g_bytes_unref (source); - if (vertex_shader == 0) - goto out; + gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3); + gsk_shader_builder_add_define (builder, "GSK_GL3", "1"); - GSK_NOTE (OPENGL, g_print ("Compiling fragment shader\n")); - source = g_resources_lookup_data (fs_path, 0, NULL); - fragment_shader = create_shader (GL_FRAGMENT_SHADER, g_bytes_get_data (source, NULL)); - g_bytes_unref (source); - if (fragment_shader == 0) - goto out; + vertex_preamble = "gl3_common.vs.glsl"; + fragment_preamble = "gl3_common.fs.glsl"; + } - self->program_id = glCreateProgram (); - glAttachShader (self->program_id, vertex_shader); - glAttachShader (self->program_id, fragment_shader); - glLinkProgram (self->program_id); +#ifdef G_ENABLE_DEBUG + if (GSK_RENDER_MODE_CHECK (SHADERS)) + gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1"); +#endif - glGetProgramiv (self->program_id, GL_LINK_STATUS, &status); - if (status == GL_FALSE) + vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER, + vertex_preamble, + "blend.vs.glsl", + &error); + if (error != NULL) { - char *buffer = NULL; - int log_len = 0; - - glGetProgramiv (self->program_id, GL_INFO_LOG_LENGTH, &log_len); - - buffer = g_malloc0 (log_len + 1); - glGetProgramInfoLog (self->program_id, log_len, NULL, buffer); - - g_critical ("Linking failure in shader:\n%s", buffer); - g_free (buffer); + g_critical ("Unable to compile vertex shader: %s", error->message); + g_error_free (error); + goto out; + } - glDeleteProgram (self->program_id); - self->program_id = 0; + fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER, + fragment_preamble, + "blend.fs.glsl", + &error); + if (error != NULL) + { + g_critical ("Unable to compile fragment shader: %s", error->message); + g_error_free (error); + goto out; + } + program_id = gsk_shader_builder_create_program (builder, + vertex_id, fragment_id, + &error); + if (error != NULL) + { + g_critical ("Unable to create program: %s", error->message); + g_error_free (error); goto out; } - /* Find the location of each uniform and attribute we use in our - * shaders - */ - self->mvp_location = glGetUniformLocation (self->program_id, "mvp"); - self->map_location = glGetUniformLocation (self->program_id, "map"); - self->parentMap_location = glGetUniformLocation (self->program_id, "parentMap"); - self->alpha_location = glGetUniformLocation (self->program_id, "alpha"); - self->position_location = glGetAttribLocation (self->program_id, "position"); - self->uv_location = glGetAttribLocation (self->program_id, "uv"); - self->blendMode_location = glGetAttribLocation (self->program_id, "blendMode"); - - GSK_NOTE (OPENGL, g_print ("Program [%d] { mvp:%u, map:%u, alpha:%u, position:%u, uv:%u }\n", - self->program_id, - self->mvp_location, - self->map_location, - self->alpha_location, - self->position_location, - self->uv_location)); - - /* We can detach and destroy the shaders from the linked program */ - glDetachShader (self->program_id, vertex_shader); - glDetachShader (self->program_id, fragment_shader); + self->program_id = program_id; + self->mvp_location = gsk_shader_builder_get_uniform_location (builder, uniforms[MVP]); + self->map_location = gsk_shader_builder_get_uniform_location (builder, uniforms[MAP]); + self->parentMap_location = gsk_shader_builder_get_uniform_location (builder, uniforms[PARENT_MAP]); + self->alpha_location = gsk_shader_builder_get_uniform_location (builder, uniforms[ALPHA]); + self->blendMode_location = gsk_shader_builder_get_uniform_location (builder, uniforms[BLEND_MODE]); + self->position_location = gsk_shader_builder_get_attribute_location (builder, attributes[POSITION]); + self->uv_location = gsk_shader_builder_get_attribute_location (builder, attributes[UV]); + + res = TRUE; out: - if (vertex_shader != 0) - glDeleteShader (vertex_shader); - if (fragment_shader != 0) - glDeleteShader (fragment_shader); + if (vertex_id > 0) + glDeleteShader (vertex_id); + if (fragment_id > 0) + glDeleteShader (fragment_id); + + g_object_unref (builder); + + return res; } static void -gsk_gl_renderer_destroy_program (GskGLRenderer *self) +gsk_gl_renderer_destroy_programs (GskGLRenderer *self) { if (self->program_id != 0) { @@ -447,7 +452,8 @@ gsk_gl_renderer_realize (GskRenderer *renderer) GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n")); gsk_gl_renderer_create_buffers (self); - gsk_gl_renderer_create_program (self); + if (!gsk_gl_renderer_create_programs (self)) + return FALSE; return TRUE; } @@ -466,7 +472,7 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer) g_clear_pointer (&self->transparent_render_items, g_array_unref); gsk_gl_renderer_destroy_buffers (self); - gsk_gl_renderer_destroy_program (self); + gsk_gl_renderer_destroy_programs (self); if (self->context == gdk_gl_context_get_current ()) gdk_gl_context_clear_current (); diff --git a/gsk/resources/glsl/blend.fs.glsl b/gsk/resources/glsl/blend.fs.glsl new file mode 100644 index 0000000000..5d2f8733d7 --- /dev/null +++ b/gsk/resources/glsl/blend.fs.glsl @@ -0,0 +1,22 @@ +vec3 BlendMultiply(vec3 Csrc, vec3 Cdst) { + return Csrc * Cdst; +} + +void main() { + vec4 src = Texture(map, vUv); + vec4 mask = Texture(parentMap, vUv); + vec3 res; + + if (blendMode == 0) { + res = src.xyz; + } + else if (blendMode == 1) { + res = BlendMultiply(src.xyz, mask.xyz); + } + else { + // Use red for debugging missing blend modes + res = vec3(1.0, 0.0, 0.0); + } + + setOutputColor(vec4(res, src.a * alpha)); +} diff --git a/gsk/resources/glsl/blend.vs.glsl b/gsk/resources/glsl/blend.vs.glsl new file mode 100644 index 0000000000..7ec059454e --- /dev/null +++ b/gsk/resources/glsl/blend.vs.glsl @@ -0,0 +1,6 @@ +void main() { + gl_Position = mvp * vec4(position, 0.0, 1.0); + + // Flip the sampling + vUv = vec2(uv.x, 1 - uv.y); +} diff --git a/gsk/resources/glsl/es2_common.fs.glsl b/gsk/resources/glsl/es2_common.fs.glsl new file mode 100644 index 0000000000..c09f75e54b --- /dev/null +++ b/gsk/resources/glsl/es2_common.fs.glsl @@ -0,0 +1,16 @@ +precision mediump float; + +uniform mat4 mvp; +uniform sampler2D map; +uniform sampler2D parentMap; +uniform float alpha; + +varying vec2 vUv; + +vec4 Texture(sampler2D sampler, vec2 texCoords) { + return texture2D(sampler, texCoords); +} + +void setOutputColor(vec4 color) { + gl_FragColor = color; +} diff --git a/gsk/resources/glsl/es2_common.vs.glsl b/gsk/resources/glsl/es2_common.vs.glsl new file mode 100644 index 0000000000..e52c153575 --- /dev/null +++ b/gsk/resources/glsl/es2_common.vs.glsl @@ -0,0 +1,7 @@ +uniform mat4 mvp; +uniform float alpha; + +attribute vec2 position; +attribute vec2 uv; + +varying vec2 vUv; diff --git a/gsk/resources/glsl/gl3-base.fs.glsl b/gsk/resources/glsl/gl3-base.fs.glsl deleted file mode 100644 index 0127556e18..0000000000 --- a/gsk/resources/glsl/gl3-base.fs.glsl +++ /dev/null @@ -1,34 +0,0 @@ -#version 150 - -smooth in vec2 vUv; - -out vec4 outputColor; - -uniform mat4 mvp; -uniform sampler2D map; -uniform sampler2D parentMap; -uniform float alpha; -uniform int blendMode; - -vec3 BlendMultiply(vec3 Csrc, vec3 Cdst) { - return Csrc * Cdst; -} - - -void main() { - vec4 src = texture2D(map, vUv); - vec4 dst = texture2D(parentMap, vUv); - vec3 res; - - if (blendMode == 0) { - res = src.xyz; - } - else if (blendMode == 1) { - res = BlendMultiply(src.xyz, dst.xyz); - } - else { - res = vec3(1.0, 1.0, 0.0); - } - - outputColor = vec4(res, src.a * alpha); -} diff --git a/gsk/resources/glsl/gl3-base.vs.glsl b/gsk/resources/glsl/gl3-base.vs.glsl deleted file mode 100644 index 534f201bfa..0000000000 --- a/gsk/resources/glsl/gl3-base.vs.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#version 150 - -uniform mat4 mvp; -uniform sampler2D map; -uniform float alpha; - -in vec2 position; -in vec2 uv; - -smooth out vec2 vUv; - -void main() { - gl_Position = mvp * vec4(position, 0.0, 1.0); - - vUv = vec2(uv.x, 1 - uv.y); -} diff --git a/gsk/resources/glsl/gl3_common.fs.glsl b/gsk/resources/glsl/gl3_common.fs.glsl new file mode 100644 index 0000000000..48134a3d8b --- /dev/null +++ b/gsk/resources/glsl/gl3_common.fs.glsl @@ -0,0 +1,19 @@ +precision highp float; + +uniform sampler2D map; +uniform sampler2D parentMap; +uniform mat4 mvp; +uniform float alpha; +uniform int blendMode; + +in vec2 vUv; + +out vec4 outputColor; + +vec4 Texture(sampler2D sampler, vec2 texCoords) { + return texture(sampler, texCoords); +} + +void setOutputColor(vec4 color) { + outputColor = color; +} diff --git a/gsk/resources/glsl/gl3_common.vs.glsl b/gsk/resources/glsl/gl3_common.vs.glsl new file mode 100644 index 0000000000..96289e6d94 --- /dev/null +++ b/gsk/resources/glsl/gl3_common.vs.glsl @@ -0,0 +1,7 @@ +uniform mat4 mvp; +uniform float alpha; + +in vec2 position; +in vec2 uv; + +out vec2 vUv; diff --git a/gsk/resources/glsl/gl_common.fs.glsl b/gsk/resources/glsl/gl_common.fs.glsl new file mode 100644 index 0000000000..e9cfa44006 --- /dev/null +++ b/gsk/resources/glsl/gl_common.fs.glsl @@ -0,0 +1,14 @@ +uniform mat4 mvp; +uniform sampler2D map; +uniform sampler2D parentMap; +uniform float alpha; + +varying vec2 vUv; + +vec4 Texture(sampler2D sampler, vec2 texCoords) { + return texture2D(sampler, texCoords); +} + +void setOutputColor(vec4 color) { + gl_FragColor = color; +} diff --git a/gsk/resources/glsl/gl_common.vs.glsl b/gsk/resources/glsl/gl_common.vs.glsl new file mode 100644 index 0000000000..e52c153575 --- /dev/null +++ b/gsk/resources/glsl/gl_common.vs.glsl @@ -0,0 +1,7 @@ +uniform mat4 mvp; +uniform float alpha; + +attribute vec2 position; +attribute vec2 uv; + +varying vec2 vUv; diff --git a/gsk/resources/glsl/gles-base.fs.glsl b/gsk/resources/glsl/gles-base.fs.glsl deleted file mode 100644 index ff43db9e6d..0000000000 --- a/gsk/resources/glsl/gles-base.fs.glsl +++ /dev/null @@ -1,11 +0,0 @@ -precision mediump float; - -uniform mat4 mvp; -uniform sampler2D map; -uniform float alpha; - -varying vec2 vUv; - -void main() { - gl_FragColor = texture2D(map, vUv) * vec4(alpha); -} diff --git a/gsk/resources/glsl/gles-base.vs.glsl b/gsk/resources/glsl/gles-base.vs.glsl deleted file mode 100644 index 747e05e157..0000000000 --- a/gsk/resources/glsl/gles-base.vs.glsl +++ /dev/null @@ -1,12 +0,0 @@ -uniform mat4 mvp; - -attribute vec2 position; -attribute vec2 uv; - -varying vec2 vUv; - -void main() { - gl_Position = mvp * vec4(position, 0.0, 1.0); - - vUv = vec2(uv.x, 1.0 - uv.y); -} -- 2.30.2